#!/bin/bash

# Script to set the system date and time.  This script is intended for use
# by the HMC's Customize Console Date/Time task.
#
# Usage:
#     customizeDateTime <date_and_time> <time_zone_info>
#
#     <date_and_time>  must be in a format appropriate for the "date" utility
#     <time_zone_info> consists of 2 or 3 blank-delimited tokens that specify
#                      the new zone's relation to GMT.  They specify the amount
#                      of time to add to GMT to get local wall time.
#         <offset_direction> is the direction of the new time zone from GMT.
#                            Denote West with "-" and East with "+".
#         <offset_hours> is the number of full hours offset from GMT
#         <offset_minutes> is an optional number of additional minutes of
#                          offset from GMT
#
#     For example:     customizeDateTime 03031729 - 4
#                      customizeDateTime 050709442002.38 + 7 15
#
# Exit status = 0 if no errors occur; non-zero otherwise.
#
# Some other things to consider doing in the future:
# . Restart the cron daemon so that it can react to the time change
# . Restart the atd daemon so that it can react to the time change
# . Turn off the display power management system (DPMS), so the screen
#      saver, etc doesn't kick in when it shouldn't.
#
# Module History:
# 00 05/18/2002  L. Brocious   Initial release
# 01 05/22/2002  L. Brocious   Add support to create time zone definition files as needed
# 02 01/10/2004  L. Brocious   Remove use of timeconfig package so this script works on
#                              MCP.  Use zic -l and hwclock --systohc instead.

actzTrace "XTODCDTT: -> customizeDateTime $*"

if (($# < 3)); then                                                         #-01
   actzTrace 'XTODCDTF: Missing required argument(s).'
   exit 1
fi

dateTime=$1
# Begin -01
offsetDirection=$2   # "+" or "-"; direction offset from GMT (- is West)
hours=$3             # Full hours offset from GMT
minutes=$4           # Additional minutes offset from GMT

# Parent directory for the time zone definition files.  This is where timeconfig looks.
timeZoneDir='/usr/share/zoneinfo'

# Set the zone name direction; it is the opposite of the zone offset direction.
# It is used in the time zone name (e.g., GMT+4, GMT-2).
if [[ $offsetDirection == "-" ]]; then
   zoneNameDirection='+'
else
   zoneNameDirection='-'
fi

# Construct the entire offset from the hours and optional minutes.
if [[ -z $minutes ]]; then
   offset=$hours
else
   offset=$hours':'$minutes
fi

timeZoneName=GMT$zoneNameDirection$offset
timeZoneFile=Etc/$timeZoneName

actzTrace "XTODCDTF: dateTime=$dateTime; time zone definition file=$timeZoneDir/$timeZoneFile"

# If the time zone definition file for the new time zone does not exist, use
# zic to create it now.  This file will be created in the standard place and
# will be usable by timeconfig.
if [[ ! -e $timeZoneDir/$timeZoneFile ]]; then
   zoneDefinition="ZONE $timeZoneFile $offsetDirection$offset - $timeZoneName"
   actzTrace "XTODCDTF: About to invoke /usr/sbin/zic -d $timeZoneDir with input=$zoneDefinition"
   if ! echo "$zoneDefinition" | /usr/sbin/zic -d $timeZoneDir -; then
      actzTrace "XTODCDTF: <- customizeDateTime; zic command failed"
      exit 2
   fi
   chgrp root $timeZoneDir/$timeZoneFile  # Set group ownership like the other zone files
fi
# End -01

# Make a backup copy of the currently active time zone definition file
# (/etc/localtime) so we can restore it if zic -l fails.  When zic -l
# fails, it leaves /etc/localtime non-existent, which causes the system to
# have a time zone of UTC, which is probably not what the caller wanted.
localtime='/etc/localtime'
tmpfile='/tmp/localtime'
if [[ -e $localtime ]]; then
   cp -p $localtime $tmpfile  # Make backup copy for error recovery
else # No localtime file; be sure no tmp file exists either.
   if [[ -e $tmpfile ]]; then
      rm -f $tmpfile
   fi
fi

# Update the time zone configuration files to reflect the new time zone.
# This must be done before the date/time are set, because they are intended
# for a specific context (the specified time zone).
actzTrace "XTODCDTF: About to issue: /usr/sbin/zic -l $timeZoneFile"
if ! /usr/sbin/zic -l $timeZoneFile; then
   if [[ -e $tmpfile ]]; then
      cp -p $tmpfile $localtime # Restore original timezone definition file
   fi
   actzTrace "XTODCDTF: <- customizeDateTime; zic -l command failed"
   exit 3
fi

# Set the system (Linux) date and time; exit if error
actzTrace "XTODCDTF: About to issue: date $dateTime"
if ! date $dateTime >/dev/null; then
   if [[ -e $tmpfile ]]; then
      cp -p $tmpfile $localtime # Restore original timezone definition file
   fi
   actzTrace "XTODCDTF: <- customizeDateTime; date command failed"
   exit 4
fi

# Set the hardware clock to the new system time, so that the time change stays
# in effect across a reboot of the operating system.
actzTrace "XTODCDTF: About to issue: /sbin/hwclock --systohc"
if ! /sbin/hwclock --systohc; then
   actzTrace "XTODCDTF: <- customizeDateTime; hwclock command failed"
   exit 5
fi

actzTrace 'XTODCDTT: <- customizeDateTime'

exit 0
